/**
 * Created by bolin on 2016/12/13.
 */
var Guid = {
    NewGuid: function () {
        var S4 = function () {
            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        };
        return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
    }
}
//从数组中删除指定ID的项
Array.prototype.Remove = function (dx) {
    var me = this;
    if (me.splice != undefined) {
        var i = 0;
        var tmp = -1;
        $.each(this, function (i, val) {
            if (this.guid == dx.guid)
                tmp = i;
            ++i;
        });
        if (tmp != -1)
            this.splice(tmp, 1);
    }
}
//数组中是否包含指定ID
Array.prototype.contains = function (dx) {
    var i = 0;
    var tmp = -1;
    var flag = false;
    $.each(this, function (i, val) {
        if (this.ID == dx.ID)
            flag = true;
    });
    return flag;
}
//根据属性名和属性值，查找第一个符合条件的对象
Array.prototype.first = function (dx, propName) {
    var i = 0;
    var tmp = undefined;
    var flag = false;
    if (propName == undefined)
        propName = "guid";
    $.each(this, function (i, val) {
        for (var i in this) {
            if (i == propName && this[i] == dx) {
                tmp = this;
                return false;
            }
        }
    });
    return tmp;
}
//根据属性名和属性值，查找第一个符合条件的对象
Array.prototype.findall = function (dx, propName) {
    var i = 0;
    var result = []
    if (propName == undefined)
        propName = "guid";
    $.each(this, function (i, val) {
        for (var i in this) {
            if (i == propName && this[i] == dx) {
                result.push(this);
            }
        }
    });
    return result;
}
function Arrow(p1, p2) {

    angle = StyleDefine.Arrow.arrowAngle * Math.PI / 180;
    var upArrow = new Point(-StyleDefine.Arrow.arrowLength * Math.cos(angle), StyleDefine.Arrow.arrowLength * Math.sin(angle));
    var downArrow = new Point(-StyleDefine.Arrow.arrowLength * Math.cos(angle), -StyleDefine.Arrow.arrowLength * Math.sin(angle));
    var slope = wf.mathHelper.Angle(p1, p2);
    upArrow.Rotation(slope.sin, slope.cos);
    downArrow.Rotation(slope.sin, slope.cos);
    upArrow.MovePoint(p2);
    downArrow.MovePoint(p2);
    return {
        "upArrow": upArrow,
        "downArrow": downArrow
    }
}

var Point = function (x, y) {
    this.X = parseFloat(x);
    this.Y = parseFloat(y);
    this.MovePoint = function (p) {
        this.X += p.X;
        this.Y += p.Y;
        return this;
    };
    this.Rotation = function (sin, cos) {
        var x = this.X;
        var y = this.Y;
        this.X = x * cos - y * sin;
        this.Y = y * cos + x * sin;
    };
}
var MathHelper = function () {
}
MathHelper.prototype = {
    //两点距离
    PointDistinct: function () {
        var x1;
        var y1;
        var x2;
        var y2;
        if (arguments.length == 2) {
            x1 = arguments[0].X;
            y1 = arguments[0].Y;
            x2 = arguments[1].X;
            y2 = arguments[1].Y;
        }
        else if (arguments.length == 4) {
            x1 = arguments[0];
            y1 = arguments[1];
            x2 = arguments[2];
            y2 = arguments[3];
        }

        return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
    },
    //计算sin，cos值
    Angle: function (p1, p2) {
        var x = p2.X - p1.X;
        var y = p2.Y - p1.Y;
        //线段长度
        var z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
        var sin = 0;
        var cos = 1;
        if (z != 0) {
            var sin = y / z;
            var cos = x / z;
        }
        return {'sin': sin, 'cos': cos};
    },
    //p1鼠标起始位置
    //p2节点原始坐标
    //p3鼠标当前位置
    Move: function (p1, p2, p3) {
        var x = p3.X - p1.X + p2.X;
        var y = p3.Y - p1.Y + p2.Y;
        return new Point(x, y);
    },
    //点p3到由p1,p2构成线段的距离
    GetNearestDistance: function (p1, p2, p3) {
        var a = this.PointDistinct(p2.X, p2.Y, p3.X, p3.Y);
        if (a <= 0.00001)
            return 0;
        var b = this.PointDistinct(p1.X, p1.Y, p3.X, p3.Y);
        if (b <= 0.00001)
            return 0;
        var c = this.PointDistinct(p1.X, p1.Y, p2.X, p2.Y);
        if (c <= 0.00001)
            return a;
        if (a * a >= b * b + c * c)
            return b;
        if (b * b >= a * a + c * c)
            return a;
        var l = (a + b + c) / 2;
        var s = Math.sqrt(l * (l - a) * (l - b) * (l - c));
        return 2 * s / c;
    },
    //p1:节点当前位置
    //p2:鼠标当前位置
    GetIntersectionPoint: function (p1, p2, p3, p4) {
        //坐标平移
        p2 = new Point(p2.X - p1.X, p2.Y - p1.Y);

        var k = 0;
        var b = 0;
        if (p3.X != p4.X) {
            k = (p3.Y - p4.Y) / (p3.X - p4.X);
            b = p3.Y - k * p3.X;
        }

        var a = p2.Y / p2.X;
        var resultX = b / (a - k);
        var resultY = a * resultX;

        return new Point(resultX + p1.X, resultY + p1.Y);


    },
    IsCaptureX: function (currentPosition, point) {
        return this.IsCapture(currentPosition, new Point(point.X, currentPosition.Y), 'x');
    },
    IsCaptureY: function (currentPosition, point) {
        return this.IsCapture(currentPosition, new Point(currentPosition.X, point.Y), 'y');
    },
    IsCapture: function (p1, p2, co) {
        var capture = {
            'iscapture': false,
            'point': new Point(0, 0),
            'dis': 0
        }

        var dis = wf.mathHelper.PointDistinct(p1, p2);
        if (dis < 10) {

            var point;
            if (co == 'x') {

                point = new Point(p2.X, p1.Y);
            }
            else {
                point = new Point(p1.X, p2.Y);
            }
            capture = {
                'iscapture': true,
                'point': point,
                'dis': dis
            }
        }
        return capture;
    },
    LineCircleIntersection: function (center, r, k, p) {


        var l = k * k + 1;
        var m = -2 * k * center.Y - 2 * center.X;
        var n = Math.pow(center.X, 2) + Math.pow(center.Y, 2) - Math.pow(r, 2);
        var dt = m * m - 4 * l * n;

        if (dt >= 0) {
            dt = Math.sqrt(dt);
            var x1 = (-m + dt) / (2 * l);
            var y1 = k * x1;

            var x2 = (-m - dt) / (2 * l);
            var y2 = k * x2;

            var dis1 = this.PointDistinct(x1, y1, p.X, p.Y);
            var dis2 = this.PointDistinct(x2, y2, p.X, p.Y);
            if (dis1 > dis2)
                return new Point(x2, y2);
            else return new Point(x1, y1);

        }
        return null;
    },
    Arrow: function (p1, p2, arrowLength) {
        var me = this;
        angle = StyleDefine.Arrow.arrowAngle * Math.PI / 180;

        if (!arrowLength)
            arrowLength = StyleDefine.Arrow.arrowLength;
        var upArrow = new Point(-arrowLength * Math.cos(angle), arrowLength * Math.sin(angle));
        var downArrow = new Point(-arrowLength * Math.cos(angle), -arrowLength * Math.sin(angle));
        var slope = me.Angle(p1, p2);
        upArrow.Rotation(slope.sin, slope.cos);
        downArrow.Rotation(slope.sin, slope.cos);
        upArrow.MovePoint(p2);
        downArrow.MovePoint(p2);
        return {
            "upArrow": upArrow,
            "downArrow": downArrow
        }
    }
}
var ActivityHelper = function () {
    this.Activitys = new Array();
}
ActivityHelper.prototype = {
    StartActivity: null,
    EndActivity: null,
    DraftingActivity: null,
    Activitys: [],

    //添加节点
    /*
     e：当前位置信息
     activityType：节点类型
     isload：调用此方法的位置
     1、从画布上手动绘制的
     2、打开或者导入流程时
     默认值 undefined
     当手动绘制时，添加规则操作会记录操作历史。
     */
    AddActivity: function (point, activityType, isload) {
        var me = this;
        // 1、移除窗体上所有空间的样式（被选中）
        wf.canvasHelper
        wf.canvasHelper.ClearAllStyle();
        var canInfo = wf.canvasHelper.InitialCanvas();
        //2、增加节点
        //var point = wf.canvasHelper.GetPoint(e);
        var activity = new Activity(activityType, point, canInfo, isload);
        if (isload == undefined) isload = false;
        if (activityType == ActivityType.branching && !isload) {
            canInfo = wf.canvasHelper.InitialCanvas();
            new Activity(ActivityType.merging, new Point(point.X + 350, point.Y), canInfo);
        }
        if (!wf.isDoubleClickCommand)
            wf.gcommand = command.nulloperation;
        if (!isload)
            toolbar.HistroyOpertion();
        return activity;
    },

    //获取所有节点的可退回节点
    /*
     此方法为递归方法，初始值为me.DraftingActivity,依此后推
     当节点没有到DraftingActivity的路径时，无法计算出前驱节点
     */
    GetReturnActivitys: function (activity) {
        var me = this;
        activity.LoopCount += 1;
        if (activity.activityType == ActivityType.drafting) {
            $.each(me.Activitys, function (i, val) {
                val.Preactivity = new Array();
            });
        }
        $.each(activity.FromRule, function (i, rule) {
            var ac = rule.endActivity;
            var isContainsNew = false
            if (activity.Preactivity == undefined)
                activity.Preactivity = new Array();
            if (ac.Preactivity.length == 0) {
                isContainsNew = true;
                $.each(activity.Preactivity, function (j, preac) {
                    ac.Preactivity.push(preac);
                });
            }
            else {
                $.each(activity.Preactivity, function (j, preac) {
                    if (!ac.Preactivity.first(preac.guid) && ac.guid != preac.guid) {
                        ac.Preactivity.push(preac);
                        isContainsNew = true;
                    }
                });
            }
            if (ac.Preactivity.first(activity.guid) == undefined) {
                ac.Preactivity.push(activity);
                isContainsNew = true;
            }
            if (isContainsNew)
                me.GetReturnActivitys(rule.endActivity);
        });
    },

    //释放所有的对象
    /*一般用于全新创建流程*/
    Dispose: function () {
        var me = this;
        for (i = me.Activitys.length - 1; i >= 0; --i) {
            if (me.Activitys[i] != undefined)
                me.Activitys[i].Dispose(true);
        }
    }

}
//画布相关操作
var CanvasHelper = function () {
}
CanvasHelper.prototype = {
    //创建流程模版
    CreateTemplate: function () {
        var me = this;
        var flag = true;
        if (wf.activityHelper != undefined)
            flag = confirm("确认新建？");
        if (flag) {
            if (wf.activityHelper == undefined)
                wf.activityHelper = new ActivityHelper();
            wf.activityHelper.Dispose();
            //activitys = new Array();
            wf.rules = new Array();

            var me = this;
            var po = StyleDefine.Window.height;
            //初始化节点
            var activity = wf.activityHelper.AddActivity(new Point(50, 50), ActivityType.start);
            wf.activityHelper.StartActivity = activity;
            var rule = new Rule(activity);
            activity = wf.activityHelper.AddActivity(new Point(170, 50), ActivityType.drafting);
            wf.activityHelper.DraftingActivity = activity;
            me.AddRule(rule, activity);
            activity = wf.activityHelper.AddActivity(new Point($(document).width() - 150, $(document).height() - 100), ActivityType.End);
            wf.activityHelper.EndActivity = activity;
            toolbar.InitailSnapshot();
        }
    },
    //清空当前模版
    //Dispose: function () {
    //    activityHelper.Dispose();
    //},
    //添加规则
    /*
     rule：wf.currentRule当前操作的规则
     activity：结束节点
     isload：调用此方法的位置
     1、从画布上手动绘制的
     2、打开或者导入流程时
     默认值 undefined
     当手动绘制时，添加规则操作会记录操作历史。
     */
    AddRule: function (rule, activity, isload) {

        wf.gcommand = command.nulloperation;
        if (rule.Points.length != 0) {
            var point = rule.GetIntersectionPoint(activity, rule.Points[rule.Points.length - 1]);
            rule.Points[rule.Points.length] = point;
        }
        else {
            var pointE = rule.GetIntersectionPoint(activity, rule.startActivity.position);
            var pointS = rule.GetIntersectionPoint(rule.startActivity, pointE);
            rule.Points[0] = pointS;
            rule.Points[1] = pointE;
        }
        rule.endActivity = activity;
        rule.startActivity.AddFromRule(rule);
        activity.AddToRule(rule);
        wf.rules[wf.rules.length] = rule;
        rule.ResetRule();
        if (isload == undefined)
            toolbar.HistroyOpertion();
    },


    //生成一个新的画布
    InitialCanvas: function () {
        var canvas = $("<canvas>").css({
            'position': 'absolute',
            "z-index": "0",
            'top': '0px',
            "left": "0px"
        }).attr({"width": StyleDefine.Window.width, "height": StyleDefine.Window.height});
        var cxt = canvas[0].getContext("2d");
        wf.workspace.append(canvas);
        return {
            'canvas': canvas,
            'cxt': cxt
        }
    },


    //获得鼠标当前位置
    GetPoint: function (e) {
        if (e != undefined) {
            if (e.offsetX != undefined)
                return new Point(e.offsetX, e.offsetY);
            else if (e.pageX != undefined) {
                return new Point(e.pageX - 36 + wf.workspace.scrollLeft(), e.pageY + wf.workspace.scrollTop());
            }
            else return e;
        }
        return e;
    },


    //根据鼠标位置获得选中的节点
    /*
     e：当前鼠标信息
     */
    GetSelectedActivity: function (e) {
        var selectedActivitys = new Array();
        var me = this;
        var point = me.GetPoint(e);
        $.each(wf.activityHelper.Activitys, function (i, val) {
            if (val.Picture.isPointInPath(point.X, point.Y)) {
                selectedActivitys[selectedActivitys.length] = val;
            }

        });

        var result = {
            'isSelect': false,
            'selectedObject': null,
            'distinct': -1
        }


        if (selectedActivitys.length > 0) {
            var minDistinct = wf.mathHelper.PointDistinct(selectedActivitys[0].position.X, selectedActivitys[0].position.Y, point.X, point.Y);
            result.selectedObject = selectedActivitys[0];
            result.distinct = minDistinct;
            result.isSelect = true;
            if (selectedActivitys.length > 1) {
                for (i = 1; i < selectedActivitys.length; i++) {
                    var dis = wf.mathHelper.PointDistinct(selectedActivitys[i].position.X, selectedActivitys[i].position.Y, point.X, point.Y);
                    if (dis < minDistinct) {
                        dis = minDistinct;
                        result.selectedObject = selectedActivitys[i];
                        result.distinct = minDistinct;
                    }
                }
            }
        }
        return result;
    },

    //根据鼠标位置获得选中的规则
    /*
     e：当前鼠标信息
     */
    GetSelectedRule: function (e) {
        var me = this;
        var result = {
            'isSelect': false,
            'selectedObject': null,
            'distinct': 1000
        }
        $.each(wf.rules, function (i, val) {
            var tmp = val.IsSelect(me.GetPoint(e));
            if (tmp.isSelect && result.distinct > tmp.distinct)
                result = tmp;
        });
        return result;
    },

    //重绘画布上的节点和规则样式
    ResetControl: function () {
        $.each(wf.activityHelper.Activitys, function (i, val) {
            val.ResetActivity();
        });
        $.each(wf.rules, function (i, val) {
            val.ResetRule();
        });
    },
    //重置画布上的节点和规则样式
    ClearAllStyle: function (e) {
        this.ClearActivityStyle(e);
        this.ClearRuleStyle();
    },

    RefreshAllStyle: function () {
        this.RefreshActivity();
        this.RefreshRule();
    },

    ClearActivityStyle: function (e) {
        $.each(wf.activityHelper.Activitys, function (i, activity) {
            activity.ChangeSelectStatus(e);
        });
    },

    RefreshActivity: function (e) {
        var me = this;
        $.each(wf.activityHelper.Activitys, function (i, activity) {
            activity.ChangeSelectStatus();
        });
    },

    RefreshRule: function () {
        $.each(wf.rules, function (i, rule) {
            rule.ResetRule();
        });
    },

    ClearRuleStyle: function () {
        $.each(wf.rules, function (i, rule) {
            rule.ChangeSelectStatus(false);
        });
    },

    DrawMovePoint: function (cxt, point, length, style) {

        var x1 = point.X - length;
        var y1 = point.Y - length;
        cxt.restore();
        cxt.beginPath();
        cxt.setTransform(1, 0, 0, 1, 0, 0);
        cxt.strokeStyle = style;
        cxt.rect(x1, y1, 2 * length, 2 * length);
        cxt.stroke();
    },


    //绘制参考线
    /*
     position当前鼠标位置
     activityId 用来确定是节点移动时的捕捉还是绘制规则时的捕捉
     节点移动时activity为移动节点
     绘制规则时传入空值*/
    GetCaptureActivity: function (method, position, activity) {
        var me = activity;
        var capture = new Array();
        $.each(wf.activityHelper.Activitys, function (i, val) {
            if (activity == undefined || val.guid != activity.guid) {
                var result = wf.mathHelper[method](position, val.position)
                if (result.iscapture) {
                    result.activity = new Array();
                    result.activity[0] = val;
                    capture[capture.length] = result;
                }
            }
        });

        if (capture.length > 0) {
            var tmp = capture[0];

            if (capture.length > 1) {
                for (i = 1; i < capture.length; i++) {
                    if (capture[i].dis < tmp.dis)
                        tmp = capture[i];
                }

            }
            return tmp;
        }
        return null;
    },


    DrawFocus: function (cxt, point) {
        cxt.restore();
        cxt.beginPath();
        cxt.setTransform(1, 0, 0, 1, 0, 0);
        cxt.strokeStyle = "rgba(225,0,0,1)";
        cxt.moveTo(-5 + point.X, -5 + point.Y);
        cxt.lineTo(5 + point.X, 5 + point.Y);
        cxt.moveTo(5 + point.X, -5 + point.Y);
        cxt.lineTo(-5 + point.X, 5 + point.Y);
        cxt.stroke();
    },

    DrawFocusInvoke: function (cxt, activitys) {

        for (i = 0; i < activitys.length; i++) {
            this.DrawFocus(cxt, activitys[i].position);
        }
    }

}
//圆角矩形
CanvasRenderingContext2D.prototype.roundRect = function (x, y, w, h, r, shadow) {


    if (w < 2 * r) r = w / 2;
    if (h < 2 * r) r = h / 2;
    this.beginPath();

    //if (shadow != undefined) {
    //    this.save();
    //    this.shadowColor = "rgba(180,180,180,90)";
    //    this.shadowOffsetX = 4;
    //    this.shadowOffsetY = 4;
    //    this.shadowBlur = 3;
    //}
    if (wf.isIe9) {
        x = -x;
        y = -y;


        this.moveTo(x, r - y);
        this.lineTo(x, y - r);
        this.arc(x - r, y - r, r, 0, Math.PI / 2);
        this.lineTo(r - x, y);
        this.arc(r - x, y - r, r, Math.PI / 2, Math.PI);
        this.lineTo(-x, r - y);
        this.arc(r - x, r - y, r, Math.PI, Math.PI * 1.5);
        this.lineTo(x - r, -y);
        this.arc(x - r, r - y, r, Math.PI * 1.5, Math.PI * 2);
        this.closePath();
        this.fillStyle = 'white';
        return this;

    }
    else {
        this.beginPath();
        this.moveTo(x + r, y);
        this.arcTo(x + w, y, x + w, y + h, r);
        this.arcTo(x + w, y + h, x, y + h, r);
        this.arcTo(x, y + h, x, y, r);
        this.arcTo(x, y, x + w, y, r);
        this.closePath();
        this.fillStyle = 'white';
        return this;
    }
}
CanvasRenderingContext2D.prototype.DrawLine = function (point1, point2, style) {

    this.setTransform(1, 0, 0, 1, 0, 0);
    this.strokeStyle = style
    this.beginPath();
    this.moveTo(point1.X, point1.Y);
    this.lineTo(point2.X, point2.Y);
    this.stroke();

}
CanvasRenderingContext2D.prototype.DrawCircle = function (x, y, r, style, isFill, shadow) {

    this.beginPath();
    this.save();
    //if (shadow != undefined) {

    //    this.shadowColor = "rgba(180,180,180,90)";
    //    this.shadowOffsetX = 2;
    //    this.shadowOffsetY = 2;
    //    this.shadowBlur = 3;
    //}
    this.arc(x, y, r, 0, Math.PI * 2, true);
    this.closePath();
    if (isFill == undefined) {
        this.fillStyle = style;
        this.fill();
    }
    else {
        this.strokeStyle = style;
        this.stroke();
    }
    this.restore();
}
